﻿using System;
using System.Collections.Generic;
using IInject.Internal;
using IInject.Registration;
using IInject.Resolution.Activation;

namespace IInject.Resolution
{
	/// <summary>
	/// 
	/// </summary>
	public class DefaultDependencyResolver : ContainerMember, ITypeDependencyResolver
	{
		#region Fields

		private IRegistryProvider _registryProvider;

		#endregion

		#region Constructors

		/// <summary>
		/// 
		/// </summary>
		/// <param name="container"></param>
		public DefaultDependencyResolver(IContainer container) : base(container)
		{
			Builder = new TypeDependencyBuilder(this, container);
			PropertyActivator = new PropertyDependencyActivator(container.Activator);
		}

		#endregion

		#region Properties

		/// <summary>
		/// 
		/// </summary>
		protected IRegistryProvider Registry
		{
			get
			{
				if (_registryProvider == null)
				{
					_registryProvider = Container.Registry;
				}

				return _registryProvider;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		protected ITypeDependencyBuilder Builder { get; private set; }

		/// <summary>
		/// 
		/// </summary>
		protected IPropertyDependencyActivator PropertyActivator { get; private set; }
	
		#endregion

		#region Methods

		public bool CanResolve(Type type)
		{
			return Registry.CanResolve(type, null);
		}

		public TypeDependency Resolve<T>()
		{
			return Resolve(typeof(T), null);
		}

		public TypeDependency Resolve<T>(string key)
		{
			return Resolve(typeof(T), key);
		}

		public TypeDependency Resolve(Type type)
		{
			return Resolve(type, null);
		}

		public TypeDependency Resolve(Type type, string key)
		{
			var context = Registry.Resolve(type, key);
			return Build(context);
		}

		public IEnumerable<TypeDependency> ResolveAll<T>()
		{
			return ResolveAll(typeof(T), null);
        }

        public IEnumerable<TypeDependency> ResolveAll<T>(string key)
        {
            return ResolveAll(typeof(T), key);
        }

        public IEnumerable<TypeDependency> ResolveAll(Type type)
        {
            return ResolveAll(type, null);
        }

		public IEnumerable<TypeDependency> ResolveAll(Type type, string key)
		{
			var results = new List<TypeDependency>();
			var contexts = Registry.ResolveAll(type, key);

			if (contexts != null)
			{
				foreach (var item in contexts)
				{
					results.Add(Build(item));
				}
			}

			return results;
		}

		public virtual TypeDependency Build(RegistryContext context)
		{
			var dependency = Builder.Build(context);
			var properties = dependency.Dependencies;

			if (properties.Count > 0)
			{
				for (int i = 0; i < properties.Count; i++)
				{
					var property = properties[i].Dependent;

					if (CanResolve(property.PropertyType))
					{
						properties[i].Parent = Resolve(property.PropertyType);
					}
				}
			}

			return dependency;
		}

		#endregion
	}
}
